#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (c) 2015  Data Enlighten Technology (Beijing) Co.,Ltd

import Lib.Logger.log4py as logging
import os
import requests
import requests.cookies
import json
import base64
import re
import time
from mj_parser import common_errors
import urllib.parse
import pickle

import pyamf.flex.messaging as messaging
import pyamf.remoting.client as service
import pyamf.remoting as remoting
import pyamf


def request_with_relogin(func):
    def func_wrapper(self, *args, **kwargs):
        returned = func(self, *args, **kwargs)
        if returned.status_code in (302, 502) or returned.headers['content-type'].startswith('text/html'):
            self.logger.debug("received status {0} for request".format(str(returned.status_code)))
            self.update_cookies()
            return func(self, *args, **kwargs)
        return returned
    return func_wrapper


def decode_amf(func):
    def func_wrapper(self, *args, **kwargs):
        returned = func(self, *args, **kwargs)
        if not returned:
            self.logger.debug('Possible login error')
            return None

        if returned.status_code < 300 and returned.headers['content-type'].startswith('application/x-amf'):
            envelope = remoting.decode(returned.content, logger=self.logger)
            return envelope
        else:
            self.logger.debug('Possible login error: {0}'.format(returned.content))

        return None

    return func_wrapper


class FordBrand:
    cookie_file = "ford_cookie.txt"
    session_file = "ford_session.txt"
    url_file = "ford_url.txt"
    user_name = "parts@A32780.caf.so"
    password = "123456"
    company_id = '53f62452e4b009ed8037682a'
    subscription_id = 'DYN0000000001A83DD'
    dsid = 'D7535353-221C-DCC8-FD1C-E95D213B38E0'
    message_id = '836760E8-62F9-9031-6E4E-6B733688A5EB'
    url = ''

class FordWebSource:
    #LOGIN = 'https://login.superservice.com/landingpage/services/authentication/loginandgoto.json'
    USER = 'https://login.superservice.com/landingpage/services/user/current.json'
    DISCOVERY = 'https://login.superservice.com/landingpage/services/application' + \
                '/info.json?preferredCompanyId={0}&rand=1487419496639'
    PROXY = {"http": "http://101.132.46.34:5870"}
    LOGIN = "http://101.132.46.34:5870/login/init/367d2633-e648-472d-a624-92e0aac0307e/4b22103d1ced0b6cabd6053f0d222664"

    def __init__(self, root_path='.', profile=FordBrand):
        self.logger = logging.get_logger("crawler", "FordWebSource." + profile.__class__.__name__)

        self.profile = profile

        self.root_path = root_path
        self.cookie_path = os.path.join(root_path, 'conf')
        self.cookie_file = os.path.join(root_path, 'conf', profile.cookie_file)
        self.session_file = os.path.join(root_path, 'conf', profile.session_file)

        self.url_file = os.path.join(root_path, 'conf', profile.url_file)
        self.data_path = os.path.join(root_path, "data")

        self.timestamp = str(int(time.time() * 1000))

        self.update_cookies()
        #self.load_url()
        #self.load_session()

    def get_data(self, str_vin, brand, group):
        envelope = self.query_vin(str_vin)
        if envelope is None:
            return common_errors.ERR_TCP_ERROR, None

        content = envelope.bodies[0][1]
        payload = content.body.body
        if payload is None:
            return common_errors.ERR_NO_VIN, None

        catalog = payload.get('catalog', None)

        if catalog is None:
            return common_errors.ERR_NO_VIN, None

        catalog_json = json.dumps(catalog, ensure_ascii=False)
        vin_file = os.path.join(self.data_path, '{0}.json'.format(str_vin))
        with open(vin_file, 'w', encoding='utf-8') as fo:
            fo.write(catalog_json)

        return common_errors.ERR_SUCCESS, vin_file

    def query_vin(self, vin):
        message = {
            'body': ['0', vin, '', 100, False, False, True, False],
            'destination': 'catalog',
            'operation': 'searchCatalogWithSections',
            'messageId': self.profile.message_id,
            'headers': {
                'X-IFM-SID': self.profile.subscription_id,
                'DSId': self.profile.dsid,
                'MARKET': 'CN',
                'X-IFM-SESSIONID': None,
                'DSEndPoint': None
            }
        }
        return self.query(message)

    @decode_amf
    @request_with_relogin
    def query(self, message_kwargs):
        client = service.RemotingService(self.profile.url, amf_version=pyamf.AMF3, logger=self.logger)
        message = (messaging.RemotingMessage(**message_kwargs),)
        request_wrapper = client.addRequest('null', *message)
        req_content = remoting.encode(client.getAMFRequest([request_wrapper])).getvalue()

        header = {
            'Content-Type': remoting.CONTENT_TYPE,
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36',
            'Referer': '',
            'Cookie': self.session['cookies']
        }

        return requests.post(self.profile.url, data=req_content, headers=header,verify=False,
                             allow_redirects=False)

    def save_url(self):
        if not os.path.exists(self.cookie_path):
            os.makedirs(self.cookie_path)
        with open(self.url_file, 'w') as fo:
            fo.write(self.profile.url)

    def load_url(self):
        with open(self.url_file, 'r') as fi:
            url = fi.read()
            if url:
                self.profile.url = url

    def save_session(self):
        if not os.path.exists(self.cookie_path):
            os.makedirs(self.cookie_path)
        with open(self.session_file, 'w') as fo:
            json.dump(self.session, fo)

    def load_session(self):
        self.session = None
        if not os.path.exists(self.session_file):
            return None
        with open(self.session_file, 'r') as fi:
            try:
                self.session = json.load(fi)
                self.logger.warning('json session: ' + str(fi))
            except Exception as e:
                self.logger.error(str(e))
        return self.session

    def update_cookies(self):
        try:
            headers = {
                'referer': self.profile.url,
                "Cookie": ""
            }

            response = requests.get(FordWebSource.LOGIN,verify=False, timeout=90)
            self.session = json.loads(base64.b64decode(response.content.decode('utf-8')).decode('utf-8'))
            self.save_session()
            self.load_session()
            headers['Cookie'] = self.session['cookies']
            returned = requests.get(self.USER, headers=headers)
            if returned.status_code == 200:
                self.profile.company_id = returned.json()['primaryAccountId']
                self.timestamp = str(int(time.time() * 1000))

            discovery_url = self.DISCOVERY.format(self.profile.company_id)
            returned = requests.get(discovery_url, headers=headers)
            if returned.status_code == 200:
                obj = returned.json()
                self.profile.url = obj['applicationInfo'][0]['url'] + '/epc/amfbroker/amf'
                self.profile.subscription_id = obj['applicationInfo'][0]['reference']['subscriptionAssignmentId']
                self.save_url()

        except requests.exceptions.ConnectTimeout:
            self.logger.error("requests.exceptions.ConnectTimeout:Login Connect Time Out")
        except requests.exceptions.Timeout:
            self.logger.error("requests.exceptions.Timeout:Login Time Out")
        except Exception as ex:
            self.logger.error(ex)
        return False

    def update_cookies_old(self):
        login_data = {
            "errorgoto": "https://login.superservice.com/login/index.html?errorCode=1",
            "goto": "https://login.superservice.com/landingpage/en-au/",
            "username": self.profile.user_name,
            "password": self.profile.password
        }
        headers = {
            'referer': self.profile.url
        }
        returned = requests.post(FordWebSource.LOGIN, data=login_data, allow_redirects=False, headers=headers)
        if returned.status_code == 303:
            cookie_obj = returned.json()
            self.cookie_str = requests.cookies.RequestsCookieJar()
            self.cookie_str.set('Authorization', cookie_obj['accessToken'], domain='login.superservice.com',
                                path='/')

            returned = requests.get(self.USER, headers=headers, cookies=self.cookie_str)
            if returned.status_code == 200:
                self.profile.company_id = returned.json()['primaryAccountId']
                self.timestamp = str(int(time.time() * 1000))

            discovery_url = self.DISCOVERY.format(self.profile.company_id)
            returned = requests.get(discovery_url, headers=headers, cookies=self.cookie_str)
            if returned.status_code == 200:
                obj = returned.json()
                self.profile.url = obj['applicationInfo'][0]['url'] + '/epc/amfbroker/amf'
                self.profile.subscription_id = obj['applicationInfo'][0]['reference']['subscriptionAssignmentId']
                self.save_url()

            parsed = urllib.parse.urlparse(self.profile.url, scheme='https')
            self.cookie_str.set('Authorization', cookie_obj['accessToken'], domain=parsed.hostname,
                                path='/')
            self.save_cookies()

    def load_cookie(self):
        self.cookie_str = None
        if not os.path.exists(self.cookie_file):
            return
        with open(self.cookie_file, 'rb') as fi:
            self.cookie_str = pickle.load(fi)


if __name__ == '__main__':
    crawler = FordWebSource('E:\\PycharmProjects\\')
    crawler.get_data('LVSHCAAE0BF687462', 'ford', '')
